package com.example.authority.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.authority.utils.MinioUtil;
import com.example.commons.entity.Files;
import com.example.authority.mapper.FileMapper;
import com.example.authority.service.FileService;

import com.example.commons.common.Result;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: authority-v3.0.7
 * @ClassName:FileController
 * @description: 文件上传控制器
 * @author:dyy
 * @Version 3.0
 **/

@RestController
@RequestMapping("/file")
public class FileController {
    @Resource
    private MinioUtil minioUtil;
    @Resource
    private FileMapper fileMapper;
    @Resource
    private FileService fileService;


    /**
     * 上传文件
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public Result upload(@RequestParam MultipartFile file) throws Exception {
        // 检查文件大小是否超过100MB
        long maxSize = 200 * 1024 * 1024;
        if (file.getSize() > maxSize) {
            return Result.error("文件过大，不可超过200MB");
        }

        String originalFilename = file.getOriginalFilename();
        String type = FileUtil.extName(originalFilename);
        String uuid = IdUtil.fastSimpleUUID();
        String category = getFileCategory(type);
        String datePath = "";
        if (!category.isEmpty()) {
            datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        }
        String folder = category.isEmpty() ? "" : category + "/" + datePath;
        String fileUUID = (folder.isEmpty() ? "" : folder + "/") + uuid + StrUtil.DOT + type;

        // 计算MD5
        String md5 = SecureUtil.md5(file.getInputStream());

        // 检查数据库是否存在相同文件
        Files dbFiles = getFileByMd5(md5);
        if (dbFiles != null) {
            return Result.success(dbFiles.getUrl());
        }

        // 上传到 MinIO
        String url = minioUtil.upload(file, fileUUID);

        // 保存到数据库
        Files saveFile = new Files();
        saveFile.setName(originalFilename);
        saveFile.setType(type);
        saveFile.setSize(file.getSize()/1024);
        saveFile.setUrl(url);
        saveFile.setMd5(md5);
        fileService.save(saveFile);

        return Result.success(url);
    }


    /**
     * 文件下载
     *
     * @param fileUUID
     * @param response
     * @throws IOException
     */
    @GetMapping("/{fileUUID}")
    public void download(@PathVariable String fileUUID, HttpServletResponse response) throws Exception {
        try (InputStream inputStream = minioUtil.download(fileUUID);
        ServletOutputStream os = response.getOutputStream()) {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
            response.setContentType("application/octet-stream");
            IoUtil.copy(inputStream, os);
        }
    }


    /**
     * md5查询文件
     *
     * @param md5
     * @return
     */
    private Files getFileByMd5(String md5) {
        // 查询文件的md5是否存在
        List<Files> filesList = fileMapper.selectList(new LambdaQueryWrapper<Files>().eq(Files::getMd5,md5));
        return filesList.size() == 0 ? null : filesList.get(0);
    }


    /**
     * 分页显示
     *
     * @param pageNum
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam(defaultValue = "") String name) {
        return Result.success(fileMapper.selectPage(new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<Files>().eq(Files::getIsDelete,false).like(Files::getName,name).orderByDesc(Files::getId)));
    }


    /**
     * 获取全部文件
     * @param
     * @param
     * @param
     * @return
     */
    @GetMapping
    public Result findALl() {return Result.success(fileService.list());}


    /**
     * 修改文件
     *
     * @param files
     * @return
     */
    @PostMapping("/update")
    public Result update(@RequestBody Files files) {return Result.success(fileService.saveOrUpdate(files));}


    /**
     * 删除文件
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        Files files = fileService.getById(id);
        files.setIsDelete(true);
        fileService.saveOrUpdate(files);
        return Result.success();
    }


    /**
     * 批量删除
     *
     * @param ids
     * @return
     */
    @DeleteMapping("/batch/{ids}")
    public Result deleteBatch(@PathVariable Long[] ids) {
      fileService.list(new LambdaQueryWrapper<Files>().in(Files::getId,ids)).forEach(files -> {
          files.setIsDelete(true);fileService.saveOrUpdate(files);
      });
        return Result.success();
    }


    /**
     * 文件类型
     *
     * @param
     * @return
     */
    private String getFileCategory(String type) {
        List<String> imageTypes = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp", "webp");
        List<String> videoTypes = Arrays.asList("mp4", "mov", "avi", "mkv", "flv", "wmv");

        if (imageTypes.contains(type.toLowerCase())) {
            return "picture";
        } else if (videoTypes.contains(type.toLowerCase())) {
            return "video";
        } else {
            return "";
        }
    }
}





